package mosdi.discovery;

import mosdi.util.SequenceUtils;

/** Class that is able to quickly compute a lower bound for the p-value
 *  of a motif with respect to the  in (given
 *  a lower bound for the expection, an upper bound for the expected
 *  clump size, and an upper bound for the number of sequences it occurs in).
 */
public class SequenceCountBoundCalculator {
	private double logMinExpectation;
	private double logMaxExpectation;
	private double stepsize;
	/** table[i] contains the (right-cumulative) distribution for  */
	private double[][] table;
	
	public SequenceCountBoundCalculator(int[] sequenceLengths, int patternLength, double minExpClumpNumberPerChar) {
		this(sequenceLengths, patternLength, minExpClumpNumberPerChar, 1000);
	}

	/** Constructor.
	 * 
	 * @param minExpClumpNumberPerChar Lower bound for the quotient of singleExpectation and expectedClumpSize
	 */
	public SequenceCountBoundCalculator(int[] sequenceLengths, int patternLength, double minExpClumpNumberPerChar, int steps) {
		if (minExpClumpNumberPerChar<=0.0) throw new IllegalArgumentException();
		this.logMinExpectation = Math.log(minExpClumpNumberPerChar);
		this.logMaxExpectation = 0.0;
		this.stepsize = (logMaxExpectation - logMinExpectation)/steps;
		table = new double[steps+1][sequenceLengths.length+1];
		for (int i=0; i<=steps; ++i) {
			double lambda = Math.exp(logMinExpectation + i*stepsize);
			double[] dist = SequenceUtils.calculateSequenceCountDistribution(sequenceLengths, lambda, patternLength, false);
			table[i][sequenceLengths.length] = dist[sequenceLengths.length];
			// compute cumulative distribution
			for (int j=sequenceLengths.length-1; j>=0; --j) {
				table[i][j] = table[i][j+1] + dist[j];
			}
		}
	}
	
	public double getPValueLowerBound(double expClumpNumberPerChar, int count) {
		double l = Math.log(expClumpNumberPerChar);
		if (l<logMinExpectation) throw new IllegalArgumentException();
		int i = (int)Math.floor((l-logMinExpectation)/stepsize);
		return table[i][count];
	}

	
}
